package com.neusoft.databus.common.utils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class JexlMath {
    private static JexlMath instance = new JexlMath();

    private JexlMath() {
    }

    public static JexlMath getInstance() {
        return JexlMath.instance;
    }

    public double pow(final double a, final double b) {
        return Math.pow(a, b);
    }

    public double max(final double... args) {
        double max = args[0];
        for (final double intVal : args) {
            max = Math.max(intVal, max);
        }
        return max;
    }

    public double min(final double... args) {
        double min = args[0];
        for (final double intVal : args) {
            min = Math.min(intVal, min);
        }
        return min;
    }

    public double avg(final double... args) {
        double sum = 0;
        for (final double intVal : args) {
            sum += intVal;
        }
        return sum / args.length;
    }

    public double sum(final double... args) {
        double sum = 0;
        for (final double intVal : args) {
            sum += intVal;
        }
        return sum;
    }

    public double minus(final double a, final double b) {
        return a - b;
    }

    public double count(final double... args) {
        return args.length;
    }

    public double fixed2(final double args) {
        final BigDecimal decimal = new BigDecimal(args);
        final BigDecimal setScale = decimal.setScale(2, BigDecimal.ROUND_HALF_DOWN);
        return setScale.doubleValue();
    }

    public String digitalOutput(final Object... params) {

        final List<Object> keyValues = Arrays.asList(params);

        if ((keyValues.size() == 0) || ((keyValues.size() / 2) == 0)) {
            JexlMath.log.warn("the params size must be odd， and at least one.");
            return "Expression Error";
        }
        final Object val = keyValues.get(0);
        String defaultValue = val.toString();

        try {
            Double doubleValue;
            if (val instanceof Number) {
                doubleValue = ((Number) val).doubleValue();
            } else if (val instanceof String) {
                try {
                    doubleValue = Double.valueOf((String) val);
                } catch (final NumberFormatException e) {
                    JexlMath.log.warn("the variable value {} is not number string.", val);
                    return val.toString();
                }
            } else {
                JexlMath.log.warn("the variable value {} is neither number nor string.", val);
                return val.toString();
            }

            final int variable = doubleValue.intValue();
            final Map<Integer, String> map = new HashMap<>();

            for (int i = 0; i < ((keyValues.size() - 1) / 2); i++) {
                final Object key = keyValues.get((i * 2) + 1);
                final Object value = keyValues.get((i * 2) + 2);
                if ("*".equals(key)) {
                    defaultValue = (String) value;
                } else {
                    map.put((int) key, (String) value);
                }
            }
            return map.containsKey(variable) ? map.get(variable) : defaultValue;
        } catch (final Exception e) {
            JexlMath.log.error(e.getMessage(), e);
        }
        return defaultValue;

    }
}
